#!/bin/sh

___temp=`pwd`
cd `dirname $0`
VL_ENV_DIR=`pwd`
cd $___temp

# 操作系统版本
# 0 - MacOS
# 1 - Linux
VL_OS_TYPE=
VL_OS_TYPE_MACOS=0
VL_OS_TYPE_LINUX=1
# VL 脚本指令名
VL_SH_NAME=`basename $0`
# vl_build.sh 脚本位置
VL_ENV_BUILD="$VL_ENV_DIR/$VL_SH_NAME"
# 环境加载脚本位置
VL_ENV="$VL_ENV_DIR/vl_env.sh"
# 工具脚本位置
VL_ENV_PART_TOOLS="$VL_ENV_DIR/vl_tools.sh"
# 指令生成脚本位置
VL_ENV_PART_GENERATE_FOR_COMMAND="$VL_ENV_DIR/vl_generate_for_command.sh"
# 构建生成脚本位置
VL_ENV_PART_GENERATE_FOR_BUILD="$VL_ENV_DIR/vl_generate_for_build.sh"
# 依赖生成脚本位置
VL_ENV_PART_GENERATE_FOR_DEP="$VL_ENV_DIR/vl_generate_for_dep.sh"
# 编译生成脚本位置
VL_ENV_PART_GENERATE_FOR_COMPILE="$VL_ENV_DIR/vl_generate_for_compile.sh"
# 构建执行步骤脚本位置
VL_ENV_PART_STEP_FOR_BUILD="$VL_ENV_DIR/vl_step_build.sh"
# 依赖执行步骤脚本位置
VL_ENV_PART_STEP_FOR_DEP="$VL_ENV_DIR/vl_step_dep.sh"
# 自动生成 Autotools 执行步骤脚本位置
VL_ENV_PART_STEP_FOR_GEN="$VL_ENV_DIR/vl_step_gen.sh"
# 编译执行步骤脚本位置
VL_ENV_PART_STEP_FOR_COMPILE="$VL_ENV_DIR/vl_step_compile.sh"

######################################################
######################################################
# 目录
######################################################
######################################################

# 项目根目录
VL_DIR_ROOT=
# 项目源码目录
VL_DIR_SRC=
# 项目 .vl-build 目录
VL_DIR_BUILD=
# 项目依赖文件存放目录
VL_DIR_DEP=
# 项目依赖文件生成目录
VL_DIR_DEP_GEN=
# 项目依赖下载临时目录
VL_DIR_DEP_TEMP=


######################################################
######################################################
# 文件
######################################################
######################################################

# 项目配置文件路径
VL_FILE_CONFIG=
# 依赖配置文件路径
VL_FILE_DEP=
# configure.ac 文件路径
VL_FILE_CONFIG_AC=
# 编译参数文件 vl_compile_options.sh 路径
VL_FILE_COMPILE_OPTIONS=

######################################################
######################################################
# 构建文件
######################################################
######################################################

# 项目配置文件修改时间戳记录文件
VL_CACHE_FILE_CONFIG_TS=

# 依赖配置文件修改时间戳记录文件
VL_CACHE_FILE_DEP_TS=

# configure.ac 时间戳记录文件
VL_CACHE_FILE_CONFIG_AC_TS=

# 依赖编译参数文件
VL_CACHE_FILE_DEP_OPTIONS=

# 依赖编译顺序文件
VL_CACHE_FILE_DEP_COMPILE_LIST=

# 编译缓存文件
VL_CACHE_FILE_COMPILE=

######################################################
######################################################
# 变量
######################################################
######################################################

# 脚本版本
VL_VERSION=1.0

# 指定的项目地址或输出地址
VL_LOCATION=

# 脚本参数数组
VL_PARAMS=("$@")
# 脚本参数
VL_PARAM=
# 脚本参数总数
VL_PARAMS_COUNT=${#VL_PARAMS[@]}
# 当前解析的脚本参数下标
VL_PARAMS_IDX=0

# 判断是否为 vl-style 项目
# 1 - 表示非 vl-style 项目
# 2 - 表示 vl-style 项目
VL_IS_PROJECT=
# 判断是否强制进行项目构建
VL_ARG_FORCE_BUILD=
# 判断是否强制进行依赖配置
VL_ARG_FORCE_DEP=
# 是否只执行配置依赖
VL_ARG_DEP_ONLY=
# AutoGen 执行方式
VL_ARG_GEN_MODE=
# 编译指定 prefix
VL_ARG_COMPILE_PREFIX=
# 编译指定 toolchain 文件
VL_ARG_COMPILE_TOOLCHAIN=
# 编译指定模式
# 1 - 编译库文件
# 2 - 编译可执行文件
# 不指定表示按照 vl-style 项目风格进行编译
VL_ARG_COMPILE_MODE=
# 表示仅编译依赖文件
VL_ARG_COMPILE_DEP_ONLY=
# 表示作为第三方依赖进行编译
# 区别在于默认配置 -lib 参数, 且编译过后不会在检查源文件是否进行过更改
VL_ARG_COMPILE_AS_DEP=
# 表示编译测试程序
VL_ARG_COMPILE_TEST=

# 项目名
VL_NAME=
# 项目类型
VL_TYPE=
# 项目依赖库
VL_DEP=

# 需要编译的依赖列表下标
VL_DEP_COMPILE_IDX=0
# 需要编译的依赖列表
VL_DEP_COMPILE_ARR=
# 需要编译的依赖版本列表
VL_DEP_COMPILE_VER=
# 需要编译的依赖模式列表
VL_DEP_COMPILE_MODE=

# 编译使用的 toolchain 文件
VL_COMPILE_CACHE_TOOLCHAIN_FILE=
# 编译使用的 toolchain 时间戳
VL_COMPILE_CACHE_TOOLCHAIN_TS=
# 编译使用的配置文件时间戳
VL_COMPILE_CACHE_OPTIONS_TS=
# 编译使用的依赖配置文件时间戳
VL_COMPILE_CACHE_DEP_OPTIONS_TS=
# 是否作为第三方依赖进行编译
VL_COMPILE_CACHE_AS_DEP=
# 编译 configure 指令
VL_COMPILE_CONFIG_COMMAND=
# 编译输出前缀
VL_COMPILE_CACHE_PREFIX=

# 用于读取脚本 configure 指令参数的变量
VL_CONFIG_ARGS_PREFIX=
VL_CONFIG_ARGS_SYSROOT=
VL_CONFIG_ARGS_HOST=
VL_CONFIG_ARGS_BUILD=
VL_CONFIG_ARGS_CC=
VL_CONFIG_ARGS_CXX=
VL_CONFIG_ARGS_AR=
VL_CONFIG_ARGS_RANLIB=
VL_CONFIG_ARGS_CXXFLAGS=
VL_CONFIG_ARGS_LIBS=
VL_CONFIG_ARGS_LDFLAGS=
VL_CONFIG_ARGS_CPPFLAGS=
VL_CONFIG_ARGS_CFLAGS=
VL_CONFIG_ARGS_LT_SYS_LIBRARY_PATH=
VL_CONFIG_ARGS_CXXCPP=

# 用于构建 configure 指令的参数变量
VL_COMPILE_CONFIG_ARGS_PREFIX=
VL_COMPILE_CONFIG_ARGS_SYSROOT=
VL_COMPILE_CONFIG_ARGS_HOST=
VL_COMPILE_CONFIG_ARGS_BUILD=
VL_COMPILE_CONFIG_ARGS_CC=
VL_COMPILE_CONFIG_ARGS_CXX=
VL_COMPILE_CONFIG_ARGS_AR=
VL_COMPILE_CONFIG_ARGS_RANLIB=
VL_COMPILE_CONFIG_ARGS_CXXFLAGS=
VL_COMPILE_CONFIG_ARGS_LIBS=
VL_COMPILE_CONFIG_ARGS_LDFLAGS=
VL_COMPILE_CONFIG_ARGS_CPPFLAGS=
VL_COMPILE_CONFIG_ARGS_CFLAGS=
VL_COMPILE_CONFIG_ARGS_LT_SYS_LIBRARY_PATH=
VL_COMPILE_CONFIG_ARGS_CXXCPP=



######################################################
######################################################
# 脚本程序入口
######################################################
######################################################


# 加载工具脚本
if ! source "$VL_ENV_PART_TOOLS" ; then
	echo "\033[31mload \"${VL_ENV_PART_TOOLS}\" failed\033[0m"
	exit 1
fi

# 识别操作系统
case "$OSTYPE" in
darwin*)
	VL_OS_TYPE=VL_OS_TYPE_MACOS
;;
*)
	VL_OS_TYPE=VL_OS_TYPE_LINUX
;;
esac

# 根据给定参数设置路径
# 参数 1 : 文件夹路径
# 
# 返回值 : 如果存在文件夹或者参数为空返回 0, 否则返回 1
function configLocation() {
	if ! checkVariable "$1" ; then
		VL_LOCATION="."
		return 0
	fi
	if checkDir "$1" ; then
		VL_LOCATION="$1"
		return 0
	fi
	printError "$1 is not an valid directroy"
	return 1
}

# 获取下一个脚本参数
# 参数会赋值给 VL_PARAM 变量
# 
# 返回值 : 如果存在参数返回 0, 否则返回 1
function nextParam() {
	VL_PARAM=
	if [ "$VL_PARAMS_IDX" -eq "$VL_PARAMS_COUNT" ] ; then
		return 1
	fi
	VL_PARAM=${VL_PARAMS[VL_PARAMS_IDX]}
	let VL_PARAMS_IDX++
	return 0
}

# 判断是否为最后一个参数
#
# 返回值 : 如果是返回 0
function isLastParam() {
	if [ "$VL_PARAMS_IDX" -ge "$VL_PARAMS_COUNT" ] ; then
		return 0
	fi
	return 1
}

# 打印解析错误文本
function printAnalyzeError() {
	echo ""
	printError "Unknown command \"${VL_PARAMS[*]}\" ..."
	echo ""
	echo "Use \"-h\" to show usage ..."
	echo
}


# 打印帮助文本
function printHelp() {
	echo ""
	echo "Virtual-Lightning Build Shell, ver $VL_VERSION, by CimZzz"
	echo ""
	echo "Usage:"
	echo ""
	echo "-h|-help|--help|help               : print help information"
	echo ""
	echo ""
	printGreen "<Generate Command>"
	echo ""
	echo "-gc|-get-config [output dir]            : generate default config file, to create project"
	echo "-gt|-get-toolchain [output dir]         : generate default compile option file, to build project"
	echo ""
	echo ""
	printGreen "<Build Command> - build vl-style project structure"
	echo ""
	echo "$VL_SH_NAME build [arguments] [project dir]"
	echo ""
	echo "Arguments:"
	echo ""
	echo "    -f|--force         : force to build project"
	echo "    -dep               : only configure dependencies"
	echo ""
	echo ""
	printGreen "<Autogen Command> - Quick to configure project by AutoTools"
	echo ""
	echo "$VL_SH_NAME gen [arguments] [project dir]"
	echo ""
	echo "Arguments:"
	echo ""
	echo "    -exec         : via \"Auto Tools\" to generate executable project files"
	echo "    -lib          : via \"Auto Tools\" to generate library project files"
	echo ""
	echo ""
	printGreen "<Compile Command> - Compile project"
	echo ""
	echo "$VL_SH_NAME compile [arguments] [project dir]"
	echo ""
	echo "Arguments:"
	echo ""
	echo "    -p|-prefix                 : set configure prefix path, default is \"/usr/local\""
	echo "    -tool|--toolchains         : set cross-compile toolchain file"
	echo "    -exec                      : compile executable project, ignore project check. if project is not \"vl-style\", must use \"-exec\" or \"-lib\" to mark project type"
	echo "    -lib                       : compile library project, ignore project check. if project is not \"vl-style\", must use \"-exec\" or \"-lib\" to mark project type"
	echo "    -as-dep                    : compile library project as denpendency"
	echo "    -dep                       : compile project's dependencies, only for \"vl-style\" project"
	echo "    -t|--test                  : compile project test program. only for \"vl-style\" project"
	echo ""
	echo ""
}

# 解析命令参数
#
# 返回值 : 如果解析成功返回 0
function analyzeParams() {
	local CMD="$VL_PARAM"
	case "$CMD" in

	# 打印 help 文本
	-h|-help|--help|help)
		printHelp
	;;


	# 生成配置文件
	-gc|-get-config)
		nextParam
		if ! configLocation "$VL_PARAM" ; then
			return 1
		fi
		
		if ! load "$VL_ENV_PART_GENERATE_FOR_COMMAND" ; then
			return 1
		fi

		if ! generateBuildConfig "$VL_LOCATION/vl_config.sh" ; then
			printError "create \"$VL_LOCATION/vl_config.sh\" failed ..."
			return 1
		fi
	;;

	# 生成 Toolchains 文件
	-gt|-get-toolchain)
		nextParam
		if ! configLocation "$VL_PARAM" ; then
			return 1
		fi
		
		if ! load "$VL_ENV_PART_GENERATE_FOR_COMMAND" ; then
			return 1
		fi

		foundNotConflictFile "VL_LOCATION" "$VL_LOCATION" "vl_toolchain" "sh"

		if ! generateToolchain "$VL_LOCATION" ; then
			printError "create \"$VL_LOCATION\" failed ..."
			return 1
		fi
	;;

	# 构建指令
	build)
		analyzeBuildCommand
		return $?
	;;

	# Auto Gen 指令
	gen)
		analyzeGenCommand
		return $?
	;;

	# Compile 指令
	compile)
		analyzeCompileCommand
		return $?
	;;
	
	*)
		echo ""
		printError "Unknown command $CMD"
		echo ""
		printError "$completelty command: $VL_SH_NAME ${VL_PARAMS[*]}"
		echo ""
		echo "Use \"-h\" to show usage"
		echo ""
		return 1
	;;
	esac

	return 0
}

# 解析构建命令
#
# 返回值 : 如果解析成功返回 0
function analyzeBuildCommand() {
	nextParam
	local CMD="$VL_PARAM"
	case "$CMD" in
	-f|--force)
		if ! defineVar "VL_ARG_FORCE_BUILD" "1" ; then
			printError "repeat argument \"$CMD\" "
			return 1
		fi
		if ! defineVar "VL_ARG_FORCE_DEP" "1" ; then
			printError "repeat argument \"$CMD\" "
			return 1
		fi
		analyzeBuildCommand
		return $?
	;;
	-dep)
		if ! defineVar "VL_ARG_DEP_ONLY" "1" ; then
			printError "repeat argument \"$CMD\" "
			return 1
		fi
		analyzeBuildCommand
		return $?
	;;
	*)
		if ! isLastParam ; then
			printAnalyzeError
			return 1
		fi
		if ! configLocation "$CMD" ; then
			return 1
		fi

		if checkVariable $VL_ARG_DEP_ONLY ; then
			# 只配置依赖模式
			if ! load "$VL_ENV_PART_STEP_FOR_DEP" ; then
				return 1
			fi
			if ! checkDependencies ; then
				return 1
			fi
		else
			# 全编译模式
			if ! load "$VL_ENV_PART_STEP_FOR_BUILD" ; then
				return 1
			fi

			if ! checkBuild ; then
				return 1
			fi
		fi
	;;
	esac
	return 0
}

# 解析 AutoGen 指令
#
# 返回值 : 如果解析成功返回 0
function analyzeGenCommand() {
	nextParam
	local CMD="$VL_PARAM"
	case "$CMD" in
	-lib)
		if ! defineVar "VL_ARG_GEN_MODE" "1" ; then
			printError "repeat argument \"$CMD\" "
			return 1
		fi
		analyzeGenCommand
		return $?
	;;
	-exec)
		if ! defineVar "VL_ARG_GEN_MODE" "2" ; then
			printError "repeat argument \"$CMD\" "
			return 1
		fi
		analyzeGenCommand
		return $?
	;;
	*)
		if ! isLastParam ; then
			printAnalyzeError
			return 1
		fi
		if ! configLocation "$CMD" ; then
			return 1
		fi

		if ! load "$VL_ENV_PART_STEP_FOR_GEN" ; then
			return 1
		fi

		if ! checkAutoGen ; then
			return 1
		fi
	;;
	esac

	return 0
}

# 解析 Compile 指令
#
# 返回值 : 如果解析成功返回 0
function analyzeCompileCommand() {
	nextParam
	local CMD="$VL_PARAM"
	case "$CMD" in
	-p|-prefix)
		# 指定 prefix
		if isLastParam ; then
			printAnalyzeError
			return 1
		fi
		nextParam
		VL_ARG_COMPILE_PREFIX="$VL_PARAM"
		analyzeCompileCommand
		return $?
	;;
	-tool|--toolchains)
		# 指定 toolchain 文件
		if isLastParam ; then
			printAnalyzeError
			return 1
		fi
		nextParam
		VL_ARG_COMPILE_TOOLCHAIN="$VL_PARAM"
		# 检查 toolchain 文件是否存在
		if ! checkFile "$VL_ARG_COMPILE_TOOLCHAIN" ; then
			printError "$VL_ARG_COMPILE_TOOLCHAIN not found"
			return 1
		fi
		# 将其转换为绝对路径
		___temp=`pwd`
		cd `dirname $VL_ARG_COMPILE_TOOLCHAIN`
		VL_ARG_COMPILE_TOOLCHAIN="${pwd}/${basename $VL_ARG_COMPILE_TOOLCHAIN}"
		cd $___temp
		analyzeCompileCommand
		return $?
	;;
	-lib)
		if ! defineVar "VL_ARG_COMPILE_MODE" "1" ; then
			printError "repeat argument \"$CMD\" "
			return 1
		fi
		VL_ARG_GEN_MODE="1"
		analyzeCompileCommand
		return $?
	;;
	-exec)
		if ! defineVar "VL_ARG_COMPILE_MODE" "2" ; then
			printError "repeat argument \"$CMD\" "
			return 1
		fi
		VL_ARG_GEN_MODE="2"
		analyzeCompileCommand
		return $?
	;;
	-as-dep)
		if ! defineVar "VL_ARG_COMPILE_MODE" "1" ; then
			printError "repeat argument \"$CMD\" "
			return 1
		fi
		VL_ARG_GEN_MODE="1"
		VL_ARG_COMPILE_AS_DEP="1"
		analyzeCompileCommand
		return $?
	;;
	-dep)
		if ! defineVar "VL_ARG_COMPILE_DEP_ONLY" "1" ; then
			printError "repeat argument \"$CMD\" "
			return 1
		fi
		analyzeCompileCommand
		return $?
	;;
	-t|--test)
		if ! defineVar "VL_ARG_COMPILE_TEST" "1" ; then
			printError "repeat argument \"$CMD\" "
			return 1
		fi
		analyzeCompileCommand
		return $?
	;;
	*)
		if ! isLastParam ; then
			printAnalyzeError
			return 1
		fi
		if ! configLocation "$CMD" ; then
			return 1
		fi

		if ! load "$VL_ENV_PART_STEP_FOR_COMPILE" ; then
			return 1
		fi

		if ! checkVariable "$VL_ARG_COMPILE_DEP_ONLY" ; then
			if ! compile ; then
				return 1
			fi
		else
			if ! compileDep ; then
				return 1
			fi
		fi
	;;
	esac

	return 0
}

if ! nextParam ; then
	printHelp
	exit 1
fi

analyzeParams
exit $?